//: observer:ObservedFlower.java
// Demonstration of "observer" pattern.
package v.book.read.tip.observer;

import java.util.Observable;
import java.util.Observer;

import junit.framework.TestCase;

class Flower {
	private boolean isOpen;
	private OpenNotifier oNotify = new OpenNotifier();
	private CloseNotifier cNotify = new CloseNotifier();

	public Flower() {
		isOpen = false;
	}

	public void open() { // Opens its petals
		isOpen = true;
		oNotify.notifyObservers();
		cNotify.open();
	}

	public void close() { // Closes its petals
		isOpen = false;
		cNotify.notifyObservers();
		oNotify.close();
	}

	public Observable opening() {
		return oNotify;
	}

	public Observable closing() {
		return cNotify;
	}

	private class OpenNotifier extends Observable {
		private boolean alreadyOpen = false;

		public void notifyObservers() {
			if (isOpen && !alreadyOpen) {
				setChanged();
				super.notifyObservers();
				alreadyOpen = true;
			}
		}

		public void close() {
			alreadyOpen = false;
		}
	}

	private class CloseNotifier extends Observable {
		private boolean alreadyClosed = false;

		public void notifyObservers() {
			if (!isOpen && !alreadyClosed) {
				setChanged();
				super.notifyObservers();
				alreadyClosed = true;
			}
		}

		public void open() {
			alreadyClosed = false;
		}
	}
}

class Bee {
	private String name;
	private OpenObserver openObsrv = new OpenObserver();
	private CloseObserver closeObsrv = new CloseObserver();

	public Bee(String nm) {
		name = nm;
	}

	// An inner class for observing openings:
	private class OpenObserver implements Observer {
		public void update(Observable ob, Object a) {
			System.out.println("Bee " + name + "'s breakfast time!");
		}
	}

	// Another inner class for closings:
	private class CloseObserver implements Observer {
		public void update(Observable ob, Object a) {
			System.out.println("Bee " + name + "'s bed time!");
		}
	}

	public Observer openObserver() {
		return openObsrv;
	}

	public Observer closeObserver() {
		return closeObsrv;
	}
}

class Hummingbird {
	private String name;
	private OpenObserver openObsrv = new OpenObserver();
	private CloseObserver closeObsrv = new CloseObserver();

	public Hummingbird(String nm) {
		name = nm;
	}

	private class OpenObserver implements Observer {
		public void update(Observable ob, Object a) {
			System.out.println("Hummingbird " + name + "'s breakfast time!");
		}
	}

	private class CloseObserver implements Observer {
		public void update(Observable ob, Object a) {
			System.out.println("Hummingbird " + name + "'s bed time!");
		}
	}

	public Observer openObserver() {
		return openObsrv;
	}

	public Observer closeObserver() {
		return closeObsrv;
	}
}

public class ObservedFlower extends TestCase {
	Flower f = new Flower();
	Bee ba = new Bee("A"), bb = new Bee("B");
	Hummingbird ha = new Hummingbird("A"), hb = new Hummingbird("B");

	public void test() {
		f.opening().addObserver(ha.openObserver());
		f.opening().addObserver(hb.openObserver());
		f.opening().addObserver(ba.openObserver());
		f.opening().addObserver(bb.openObserver());
		f.closing().addObserver(ha.closeObserver());
		f.closing().addObserver(hb.closeObserver());
		f.closing().addObserver(ba.closeObserver());
		f.closing().addObserver(bb.closeObserver());
		// Hummingbird B decides to sleep in:
		f.opening().deleteObserver(hb.openObserver());
		// A change that interests observers:
		f.open();
		f.open(); // It's already open, no change.
		// Bee A doesn't want to go to bed:
		f.closing().deleteObserver(ba.closeObserver());
		f.close();
//		f.close(); // It's already closed; no change
		f.opening().deleteObservers();
		f.open();
		f.close();
	}

	public static void main(String args[]) {
		junit.textui.TestRunner.run(ObservedFlower.class);
//		DecimalFormat df = new DecimalFormat("#.00");
//        System.out.println();
//		for (int i = 1; i < 100; i++) {
//			System.out.println(i+"年后的房价"+200 * Math.pow(1.1, i));
//			System.out.println("第"+i+"年，还差" + df.format((200 * Math.pow(1.1, i) - 40 * i))+"W");
//		}
//		System.out.println("end");
	}
} // /:~
